namespace NHCodeFirst.FluentMapper
{
    using System;
    using Enums;
    using HbmModel;

    public class CollectionMapperBase<TChild>
    {
        private readonly TChild child;
        private readonly Collection collection;

        internal CollectionMapperBase(TChild child, Collection collection)
        {
            this.child = child;
            this.collection = collection;
        }

        public TChild Access(Access access, Naming? namingStrategy = null)
        {
            return Access(access.ToString().ToLower(), namingStrategy);
        }

        public TChild Access<T>(Naming? namingStrategy = null)
        {
            return Access(typeof(T).FullName, namingStrategy);
        }

        public TChild Access(Type type, Naming? namingStrategy = null)
        {
            return Access(type.FullName, namingStrategy);
        }

        public TChild Table(string name, string schema = "dbo")
        {
            collection.Table = name;
            collection.Schema = schema;
            return child;
        }

        public TChild Catalog(string value)
        {
            collection.Catalog = value;
            return child;
        }

        public TChild SubSelect(string value)
        {
            collection.SubSelect = value;
            return child;
        }

        public TChild Lazy(CollectionLazy value)
        {
            collection.Lazy = value.ToString().ToLower();
            return child;
        }

        public TChild Inverse(bool lazy)
        {
            collection.Inverse = lazy.ToString().ToLower();
            return child;
        }

        public TChild Mutable(bool value)
        {
            collection.Mutable = value.ToString().ToLower();
            return child;
        }

        public TChild Cascade(CollectionCascade value)
        {
            switch (value)
            {
                case CollectionCascade.All:
                    collection.Cascade = "all";
                    break;
                case CollectionCascade.AllDeleteOrphan:
                    collection.Cascade = "all-delete-orphan";
                    break;
                case CollectionCascade.Delete:
                    collection.Cascade = "delete";
                    break;
                case CollectionCascade.None:
                    collection.Cascade = "none";
                    break;
                case CollectionCascade.SaveUpdate:
                    collection.Cascade = "save-update";
                    break;
            }
            return child;
        }

        public TChild OrderBy(string value)
        {
            collection.OrderBy = value;
            return child;
        }

        public TChild Where(string value)
        {
            collection.Where = value;
            return child;
        }

        public TChild BatchSize(int value)
        {
            collection.BatchSize = value.ToString();
            return child;
        }

        public TChild OuterJoin(JoinStrategy value)
        {
            collection.OuterJoin = value.ToString().ToLower();
            return child;
        }

        public TChild Fetch(CollectionFetchMode value)
        {
            collection.Fetch = value.ToString().ToLower();
            return child;
        }

        public TChild Persister<TPersister>()
        {
            collection.Persister = typeof (TPersister).FullName;
            return child;
        }

        public TChild Persister(Type value)
        {
            collection.Persister = value.FullName;
            return child;
        }

        public TChild CollectionType(string value)
        {
            collection.CollectionType = value;
            return child;
        }

        public TChild Check(string value)
        {
            collection.Check = value;
            return child;
        }

        public TChild OptimisticLock(bool value)
        {
            collection.OptimisticLock = value.ToString().ToLower();
            return child;
        }

        private TChild Access(string access, Naming? naming)
        {
            collection.Access = access;
            if (naming.HasValue)
                collection.Access += "." + EnumsToHbmString.GetAccessNamingStrategy(naming.Value);
            return child;
        }
    }
}